<!DOCTYPE html>
<html lang="zh-CN">
    <!-- title -->


    

<!-- keywords -->



<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="author" content="Lolipop">
    <meta name="renderer" content="webkit">
    <meta name="copyright" content="Lolipop">
    
        <meta name="keywords" content="Lolipop,frontend,full-stack,前端,全栈">
    
    <meta name="description" content="">
    <meta name="description" content="类（Class）是用于创建对象的模板，他们用代码封装数据以处理该数据，是面向对象编程方法的重要特性之一。JavaScript 中的 class 语法在 ES6 中引入，其底层实现基于原型（Prototype），系原型继承的语法糖（Syntactic Sugar）。 本博文将探讨 JavaScript 中如何使用类的相关知识，文章组织架构和内容基于 MDN 上关于类的章节。 定义类类可以被看作一种“">
<meta property="og:type" content="article">
<meta property="og:title" content="漫谈 JavsScript 类（Class）的使用">
<meta property="og:url" content="https://lolipopj.github.io/2021/05/19/js-use-class/index.html">
<meta property="og:site_name" content="Lolipop">
<meta property="og:description" content="类（Class）是用于创建对象的模板，他们用代码封装数据以处理该数据，是面向对象编程方法的重要特性之一。JavaScript 中的 class 语法在 ES6 中引入，其底层实现基于原型（Prototype），系原型继承的语法糖（Syntactic Sugar）。 本博文将探讨 JavaScript 中如何使用类的相关知识，文章组织架构和内容基于 MDN 上关于类的章节。 定义类类可以被看作一种“">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-05-19T16:00:00.000Z">
<meta property="article:modified_time" content="2021-05-19T16:00:00.000Z">
<meta property="article:author" content="Lolipop">
<meta property="article:tag" content="JavaScript">
<meta property="article:tag" content="ES6">
<meta name="twitter:card" content="summary">
    <meta http-equiv="Cache-control" content="no-cache">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <link rel="icon" href="https://cdn.jsdelivr.net/gh/lolipopj/LolipopJ.github.io/static/assets/favicon.ico">
    
    <title>漫谈 JavsScript 类（Class）的使用 · Lolipop&#39;s Studio</title>
    <!-- /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
/* This file is meant as a standalone workflow for
- testing support for link[rel=preload]
- enabling async CSS loading in browsers that do not support rel=preload
- applying rel preload css once loaded, whether supported or not.
*/ -->
<script>
    (function (w) {
        'use strict'
        // rel=preload support test
        if (!w.loadCSS) {
            w.loadCSS = function () {}
        }
        // define on the loadCSS obj
        var rp = (loadCSS.relpreload = {})
        // rel=preload feature support test
        // runs once and returns a function for compat purposes
        rp.support = (function () {
            var ret
            try {
                ret = w.document.createElement('link').relList.supports('preload')
            } catch (e) {
                ret = false
            }
            return function () {
                return ret
            }
        })()

        // if preload isn't supported, get an asynchronous load by using a non-matching media attribute
        // then change that media back to its intended value on load
        rp.bindMediaToggle = function (link) {
            // remember existing media attr for ultimate state, or default to 'all'
            var finalMedia = link.media || 'all'

            function enableStylesheet() {
                link.media = finalMedia
            }

            // bind load handlers to enable media
            if (link.addEventListener) {
                link.addEventListener('load', enableStylesheet)
            } else if (link.attachEvent) {
                link.attachEvent('onload', enableStylesheet)
            }

            // Set rel and non-applicable media type to start an async request
            // note: timeout allows this to happen async to let rendering continue in IE
            setTimeout(function () {
                link.rel = 'stylesheet'
                link.media = 'only x'
            })
            // also enable media after 3 seconds,
            // which will catch very old browsers (android 2.x, old firefox) that don't support onload on link
            setTimeout(enableStylesheet, 3000)
        }

        // loop through link elements in DOM
        rp.poly = function () {
            // double check this to prevent external calls from running
            if (rp.support()) {
                return
            }
            var links = w.document.getElementsByTagName('link')
            for (var i = 0; i < links.length; i++) {
                var link = links[i]
                // qualify links to those with rel=preload and as=style attrs
                if (
                    link.rel === 'preload' &&
                    link.getAttribute('as') === 'style' &&
                    !link.getAttribute('data-loadcss')
                ) {
                    // prevent rerunning on link
                    link.setAttribute('data-loadcss', true)
                    // bind listeners to toggle media back
                    rp.bindMediaToggle(link)
                }
            }
        }

        // if unsupported, run the polyfill
        if (!rp.support()) {
            // run once at least
            rp.poly()

            // rerun poly on an interval until onload
            var run = w.setInterval(rp.poly, 500)
            if (w.addEventListener) {
                w.addEventListener('load', function () {
                    rp.poly()
                    w.clearInterval(run)
                })
            } else if (w.attachEvent) {
                w.attachEvent('onload', function () {
                    rp.poly()
                    w.clearInterval(run)
                })
            }
        }

        // commonjs
        if (typeof exports !== 'undefined') {
            exports.loadCSS = loadCSS
        } else {
            w.loadCSS = loadCSS
        }
    })(typeof global !== 'undefined' ? global : this)
</script>

    <style type="text/css">
    @font-face {
        font-family: 'Oswald-Regular';
        src: url("/font/Oswald-Regular.ttf");
    }

    body {
        margin: 0;
    }

    header,
    footer,
    .back-top,
    .sidebar,
    .container,
    .site-intro-meta,
    .toc-wrapper {
        display: none;
    }

    .site-intro {
        position: relative;
        z-index: 3;
        width: 100%;
        /* height: 50vh; */
        overflow: hidden;
    }

    .site-intro-placeholder {
        position: absolute;
        z-index: -2;
        top: 0;
        left: 0;
        width: calc(100% + 300px);
        height: 100%;
        background: repeating-linear-gradient(-45deg, #444 0, #444 80px, #333 80px, #333 160px);
        background-position: center center;
        transform: translate3d(-226px, 0, 0);
        animation: gradient-move 2.5s ease-out 0s infinite;
    }

    @keyframes gradient-move {
        0% {
            transform: translate3d(-226px, 0, 0);
        }
        100% {
            transform: translate3d(0, 0, 0);
        }
    }
</style>

    <link rel="preload" href="/css/style.css?v=20211217" as="style" onload="this.onload=null;this.rel='stylesheet'">
    <link rel="preload" href="/css/dark.css?v=20211217" as="style">
    <link rel="stylesheet" href="/css/dark.css">
    <link rel="stylesheet" href="/css/mobile.css?v=20211217" media="(max-width: 960px)">
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" as="script">
    <link rel="preload" href="/scripts/main.js?v=20211217" as="script">
    <link rel="preload" href="/scripts/dark.js?v=20211217" as="script">
    <link rel="preload" href="/font/Oswald-Regular.ttf" as="font" crossorigin>
    <link rel="preload" href="https://at.alicdn.com/t/font_327081_1dta1rlogw17zaor.woff" as="font" crossorigin>
    <!-- algolia -->
    
        <script>
            var hits = JSON.parse('{"per_page":10}')
            var labels = JSON.parse('{"input_placeholder":"搜索博客","hits_empty":"Ops，我未能提供任何搜索结果：${query}","hits_stats":"在 ${time} ms 内找到了 ${hits} 个结果"}')

            var algolia = {
                applicationID: 'V9YD7AWBOS',
                apiKey: '5cb206cb0658a9daff865eef79de4bc4',
                indexName: 'lolipopJ.github.io',
                hits: hits,
                labels: labels
            }
        </script>
    
    <!-- 百度统计  -->
    
    <!-- 谷歌统计  -->
    
<meta name="generator" content="Hexo 5.4.1"><link rel="alternate" href="/atom.xml" title="Lolipop" type="application/atom+xml">
</head>

    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
    <script type="text/javascript">
        if (typeof window.$ == undefined) {
            console.warn('jquery load from jsdelivr failed, will load local script')
            document.write('<script src="/lib/jquery.min.js" />')
        }
    </script>
    
        <body class="post-body">
    
        <!-- header -->
        <header class="header header-mobile">
    <!-- top read progress line -->
    <div class="header-element">
        <div class="read-progress read-progress-feature"></div>
    </div>
    <!-- sidebar menu button -->
    <div class="header-element">
        
            <div class="header-sidebar-menu header-sidebar-menu-rounded">
        
            
                <i class="fas fa-bars"></i>
            
        </div>
    </div>
    <!-- header actions -->
    <div class="header-actions">
        <!-- theme mode switch button -->
        <span class="header-theme-btn header-element">
            <i class="fas fa-adjust"></i>
        </span>
        <!-- back to home page text -->
        <span class="home-link header-element">
            <a href=/>Lolipop's Studio.</a>
        </span>
    </div>
    <!-- toggle banner for post layout -->
    
        
            <div class="banner banner-clean">
        
            <div class="blog-title header-element">
                <a href="/">Lolipop&#39;s Studio.</a>
            </div>
            <div class="post-title header-element">
                <a href="#" class="post-name">漫谈 JavsScript 类（Class）的使用</a>
            </div>
        </div>
    
</header>

        <!-- fixed footer -->
        <footer class="footer-fixed">
    <!-- back to top button -->
    <div class="footer-fixed-element">
        
            <div class="back-top back-top-hidden back-top-rounded">
        
        
            <i class="fas fa-chevron-up"></i>
        
        </div>
    </div>
</footer>

        <!-- wrapper -->
        <div class="wrapper">
            <div class="site-intro" style="







    height:50vh;

">
    
    <!-- 主页  -->
    
        
    <!-- 404页  -->
            
    <div class="site-intro-placeholder"></div>
    <div class="site-intro-img" style="background-image: url(https://source.unsplash.com/1600x900/?coder)"></div>
    <div class="site-intro-meta">
        <!-- 标题  -->
        <h1 class="intro-title">
            <!-- 主页  -->
            
                漫谈 JavsScript 类（Class）的使用
            <!-- 404 -->
            
        </h1>
        <!-- 副标题 -->
        <p class="intro-subtitle">
            <!-- 主页副标题  -->
            
                
            <!-- 404 -->
            
        </p>
        <!-- 文章页 meta -->
        
            <div class="post-intros">
                <!-- 文章页标签  -->
                
                    <div class= post-intro-tags >
    
        
        
            
        
        
        <span class="post-category" data-categories="技术琐事"">
            <i class="fas fa-folder post-category-icon"></i>
            <span class="post-category-text">
                技术琐事
            </span>
        </span>
    
    
        <a class="post-tag" href="javascript:void(0);" data-tags="JavaScript">JavaScript</a>
    
        <a class="post-tag" href="javascript:void(0);" data-tags="ES6">ES6</a>
    
</div>

                
                
                    <div class="post-intro-read">
                        <span>字数统计: <span class="post-count word-count">4.9k</span>阅读时长: <span class="post-count reading-time">20 min</span></span>
                    </div>
                
                <div class="post-intro-meta">
                    <!-- 撰写日期 -->
                    <span class="iconfont-archer post-intro-calander">&#xe676;</span>
                    <span class="post-intro-time">2021/05/20</span>
                    <!-- busuanzi -->
                    
                        <span id="busuanzi_container_page_pv" class="busuanzi-pv">
                            <span class="iconfont-archer post-intro-busuanzi">&#xe602;</span>
                            <span id="busuanzi_value_page_pv"></span>
                        </span>
                    
                    <!-- 文章分享 -->
                    <span class="share-wrapper">
                        <span class="iconfont-archer share-icon">&#xe71d;</span>
                        <span class="share-text">Share</span>
                        <ul class="share-list">
                            <li class="iconfont-archer share-qr" data-type="qr">&#xe75b;
                                <div class="share-qrcode"></div>
                            </li>
                            <li class="iconfont-archer" data-type="weibo">&#xe619;</li>
                            <li class="iconfont-archer" data-type="qzone">&#xe62e;</li>
                            <li class="iconfont-archer" data-type="twitter">&#xe634;</li>
                            <li class="iconfont-archer" data-type="facebook">&#xe67a;</li>
                        </ul>
                    </span>
                </div>
            </div>
        
    </div>
</div>

            <script>
  // get user agent
  function getBrowserVersions() {
    var u = window.navigator.userAgent
    return {
      userAgent: u,
      trident: u.indexOf('Trident') > -1, //IE内核
      presto: u.indexOf('Presto') > -1, //opera内核
      webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
      gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
      mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
      ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
      android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
      iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者安卓QQ浏览器
      iPad: u.indexOf('iPad') > -1, //是否为iPad
      webApp: u.indexOf('Safari') == -1, //是否为web应用程序，没有头部与底部
      weixin: u.indexOf('MicroMessenger') == -1, //是否为微信浏览器
      uc: u.indexOf('UCBrowser') > -1, //是否为android下的UC浏览器
    }
  }
  var browser = {
    versions: getBrowserVersions(),
  }
  console.log('userAgent: ' + browser.versions.userAgent)

  // callback
  function fontLoaded() {
    console.log('font loaded')
    if (document.getElementsByClassName('site-intro-meta')) {
      document
        .getElementsByClassName('intro-title')[0]
        .classList.add('intro-fade-in')
      document
        .getElementsByClassName('intro-subtitle')[0]
        .classList.add('intro-fade-in')
      var postIntros = document.getElementsByClassName('post-intros')[0]
      if (postIntros) {
        postIntros.classList.add('post-fade-in')
      }
    }
  }

  // UC不支持跨域，所以直接显示
  function asyncCb() {
    if (browser.versions.uc) {
      console.log('UCBrowser')
      fontLoaded()
    } else {
      WebFont.load({
        custom: {
          families: ['Oswald-Regular'],
        },
        loading: function () {
          // 所有字体开始加载
          // console.log('font loading');
        },
        active: function () {
          // 所有字体已渲染
          fontLoaded()
        },
        inactive: function () {
          // 字体预加载失败，无效字体或浏览器不支持加载
          console.log('inactive: timeout')
          fontLoaded()
        },
        timeout: 5000, // Set the timeout to two seconds
      })
    }
  }

  function asyncErr() {
    console.warn('script load from CDN failed, will load local script')
  }

  // load webfont-loader async, and add callback function
  function async(u, cb, err) {
    var d = document,
      t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0]
    o.src = u
    if (cb) {
      o.addEventListener(
        'load',
        function (e) {
          cb(null, e)
        },
        false
      )
    }
    if (err) {
      o.addEventListener(
        'error',
        function (e) {
          err(null, e)
        },
        false
      )
    }
    s.parentNode.insertBefore(o, s)
  }

  var asyncLoadWithFallBack = function (arr, success, reject) {
    var currReject = function () {
      reject()
      arr.shift()
      if (arr.length) async(arr[0], success, currReject)
    }

    async(arr[0], success, currReject)
  }

  asyncLoadWithFallBack(
    [
      'https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.min.js',
      'https://cdn.bootcss.com/webfont/1.6.28/webfontloader.js',
      "/lib/webfontloader.min.js",
    ],
    asyncCb,
    asyncErr
  )
</script>

            <img class="loading" src="/assets/loading.svg" style="display: block; margin: 6rem auto 0 auto; width: 6rem; height: 6rem;" />
            <div class="container container-unloaded">
                <main class="main post-page">
    <article class="article-entry">
        <p>类（Class）是用于创建对象的模板，他们用代码封装数据以处理该数据，是面向对象编程方法的重要特性之一。JavaScript 中的 <code>class</code> 语法在 ES6 中引入，其底层实现基于原型（Prototype），系原型继承的语法糖（Syntactic Sugar）。</p>
<p>本博文将探讨 JavaScript 中<strong>如何使用类</strong>的相关知识，文章组织架构和内容基于 MDN 上关于类的<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">章节</a>。</p>
<h2 id="定义类"><a href="#定义类" class="headerlink" title="定义类"></a>定义类</h2><p>类可以被看作一种“特殊的函数”，和函数的定义方法一样，类的定义方法有两种：<strong>类声明</strong>和<strong>类表达式</strong>。</p>
<p>第一种方法是，直接使用 <code>class</code> 关键字声明类，即<strong>类声明</strong>的方法。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>但是，与函数声明不同的是，使用类声明的方式<strong>不会提升</strong>。这意味着必须先声明类，再使用它。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> u = <span class="keyword">new</span> <span class="title class_">User</span>() <span class="comment">// Uncaught ReferenceError: User is not defined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>另一种方法是，将 <code>class</code> 声明的类赋值给变量，即<strong>类表达式</strong>的方法。类表达式可以命名或匿名，其中，命名类表达式的名称（类的 <code>name</code> 属性）是该类体的局部名称。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 匿名类</span></span><br><span class="line"><span class="keyword">let</span> <span class="title class_">User</span> = <span class="keyword">class</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">User</span>.<span class="property">name</span>) <span class="comment">// User</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 命名类</span></span><br><span class="line"><span class="keyword">let</span> <span class="title class_">User</span> = <span class="keyword">class</span> <span class="title class_">Admin</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">User</span>.<span class="property">name</span>) <span class="comment">// Admin</span></span><br></pre></td></tr></table></figure>

<p>同样，使用类表达式的方式也<strong>不会提升</strong>。</p>
<p>定义类之后，就可以使用 <code>new</code> 关键字实例化类了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> u = <span class="keyword">new</span> <span class="title class_">User</span>()</span><br></pre></td></tr></table></figure>

<h2 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h2><p><code>constructor()</code> 方法或<strong>构造函数</strong>，是用于创建和初始化一个由 <code>class</code> 创建的对象的特殊方法，一个类只能拥有一个 <code>constructor()</code> 方法。</p>
<p>如果一个类中有构造函数，那么执行 <code>new</code> 创建实例时，将调用这个构造函数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">name, gender</span>) &#123; <span class="comment">// 构造函数</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">gender</span> = gender</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> u = <span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&#x27;Ming&#x27;</span>, <span class="string">&#x27;Male&#x27;</span>) <span class="comment">// 初始化对象</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(u.<span class="property">name</span>, u.<span class="property">gender</span>) <span class="comment">// Ming Male</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> u2 = <span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&#x27;Xiao&#x27;</span>) <span class="comment">// 初始化赋值参数少于构造函数参数时</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(u2.<span class="property">name</span>, u2.<span class="property">gender</span>) <span class="comment">// Xiao undefined</span></span><br></pre></td></tr></table></figure>

<p>对于 <code>new</code> 创建实例时的每个参数，将依次赋值给构造函数。多余的参数将被忽略。</p>
<p>特别的，<code>constructor()</code> 方法中可以使用 <code>super</code> 关键字调用父类的 <code>constructor()</code> 方法。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">name, gender</span>) &#123; <span class="comment">// User 类的构造函数</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">gender</span> = gender</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Admin</span> <span class="keyword">extends</span> <span class="title class_ inherited__">User</span> &#123; <span class="comment">// 使用 extends 创建 User 的子类 Admin</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">name, gender, openId</span>) &#123; <span class="comment">// Admin 类的构造函数</span></span><br><span class="line">        <span class="variable language_">super</span>(name, gender) <span class="comment">// 调用父类 User 的构造函数</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">openId</span> = openId</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> a = <span class="keyword">new</span> <span class="title class_">Admin</span>(<span class="string">&#x27;Ming&#x27;</span>, <span class="string">&#x27;Male&#x27;</span>, <span class="string">&#x27;xxx489&#x27;</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a.<span class="property">name</span>, a.<span class="property">gender</span>, a.<span class="property">openId</span>) <span class="comment">// Ming Male xxx489</span></span><br></pre></td></tr></table></figure>

<h2 id="原型方法"><a href="#原型方法" class="headerlink" title="原型方法"></a>原型方法</h2><p>在类体中可以声明函数方法。从底层实现来看，这些方法将会在对象的原型链上定义出来，故称作<strong>原型方法</strong>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Rectangle</span> &#123;</span><br><span class="line">    <span class="comment">// Field declarations</span></span><br><span class="line">    log = [] <span class="comment">// 日志属性</span></span><br><span class="line">    <span class="comment">// Constructor</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">height, width</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">height</span> = height</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">width</span> = width</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Getter</span></span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">area</span>() &#123; <span class="comment">// 获取当前的面积</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">calcArea</span>()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Setter</span></span><br><span class="line">    <span class="keyword">set</span> <span class="title function_">height</span>(<span class="params">h</span>) &#123; <span class="comment">// 修改 height 属性时添加日志</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_height</span> = h <span class="comment">// 如果为 this.height = h 会循环调用这个 Setter，发生堆栈溢出</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">log</span>.<span class="title function_">push</span>(<span class="string">`set height: <span class="subst">$&#123;h&#125;</span>`</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span> <span class="title function_">width</span>(<span class="params">w</span>) &#123; <span class="comment">// 修改 width 属性时添加日志</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_width</span> = w</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">log</span>.<span class="title function_">push</span>(<span class="string">`set width: <span class="subst">$&#123;w&#125;</span>`</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Method</span></span><br><span class="line">    <span class="title function_">calcArea</span>(<span class="params"></span>) &#123; <span class="comment">// 计算当前的面积</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_height</span> * <span class="variable language_">this</span>.<span class="property">_width</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> rec = <span class="keyword">new</span> <span class="title class_">Rectangle</span>(<span class="number">5</span>, <span class="number">10</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(rec.<span class="property">log</span>) <span class="comment">// [&quot;set height: 5&quot;, &quot;set width: 10&quot;]</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(rec.<span class="property">area</span>) <span class="comment">// 50</span></span><br><span class="line"></span><br><span class="line">rec.<span class="property">height</span> = <span class="number">10</span></span><br><span class="line">rec.<span class="property">width</span> = <span class="number">20</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(rec.<span class="property">log</span>) <span class="comment">// [&quot;set height: 5&quot;, &quot;set width: 10&quot;, &quot;set height: 10&quot;, &quot;set width: 20&quot;]</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(rec.<span class="property">area</span>) <span class="comment">// 200</span></span><br></pre></td></tr></table></figure>

<p>上面的类中定义计算当前面积的方法 <code>calcArea()</code> 时，使用了 ES6 引入的<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions">更简短的定义语法</a>，这种语法与 Setter 和 Getter 的语法相似，它直接将方法名赋值给了函数。</p>
<p>此外，由于 Setter 的特性，当我们在构造函数执行赋值操作，以及之后修改实例的属性时，将调用 Setter 的方法（即 Hook 函数）。因此在上面代码中的 <code>rec</code> 实例中，并不存在 <code>height</code> 和 <code>width</code> 属性，取而代之的是 <code>_height</code> 和 <code>_width</code> 属性。</p>
<h2 id="静态方法和属性"><a href="#静态方法和属性" class="headerlink" title="静态方法和属性"></a>静态方法和属性</h2><p>在类的方法前面添加关键字 <code>static</code> 可以定义<strong>静态方法</strong>或<strong>静态属性</strong>，它们可以通过类直接调用，但不能通过类的实例调用。静态方法和静态属性常用于为一个使用类的应用程序创建工具函数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">x, y</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">x</span> = x</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">y</span> = y</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> className = <span class="string">&#x27;Point&#x27;</span> <span class="comment">// 定义 Point 类的静态属性</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="title function_">distance</span>(<span class="params">a, b</span>) &#123; <span class="comment">// 定义 Point 类的静态方法</span></span><br><span class="line">        <span class="keyword">const</span> dx = a.<span class="property">x</span> - b.<span class="property">x</span></span><br><span class="line">        <span class="keyword">const</span> dy = a.<span class="property">y</span> - b.<span class="property">y</span></span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">hypot</span>(dx, dy) <span class="comment">// Math.hypot() 返回所有参数的平方和的平方根，在此处用于求两点之间的距离</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> p1 = <span class="keyword">new</span> <span class="title class_">Point</span>(<span class="number">5</span>, <span class="number">5</span>)</span><br><span class="line"><span class="keyword">const</span> p2 = <span class="keyword">new</span> <span class="title class_">Point</span>(<span class="number">10</span>,<span class="number">10</span>)</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="property">className</span>) <span class="comment">// undefined</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(p1.<span class="property">distance</span>) <span class="comment">// undefined</span></span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Point</span>.<span class="property">className</span>) <span class="comment">// Point</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Point</span>.<span class="title function_">distance</span>(p1, p2)) <span class="comment">// 7.0710678118654755</span></span><br></pre></td></tr></table></figure>

<p>上面的代码中，当我们使用实例访问静态方法和属性时，会显示 <code>undefined</code>。而当我们使用类来访问时，则能正常调用了。</p>
<h2 id="原型方法和静态方法中的-this"><a href="#原型方法和静态方法中的-this" class="headerlink" title="原型方法和静态方法中的 this"></a>原型方法和静态方法中的 <code>this</code></h2><p>当调用静态或原型方法时没有指定 <code>this</code> 的值，那么方法内的 <code>this</code> 值将被置为 <code>undefined</code>。这是因为 <code>class</code> 内部的代码总是在<strong>严格模式</strong>下执行。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span> &#123;</span><br><span class="line">    <span class="title function_">getThis</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> <span class="title function_">getStaticThis</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> obj = <span class="keyword">new</span> <span class="title class_">MyClass</span>()</span><br><span class="line"><span class="keyword">const</span> getObjThis = obj.<span class="property">getThis</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="title function_">getThis</span>()) <span class="comment">// obj 实例对象（指定了 this 的初值，在这里相当于 console.log(obj)）</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getObjThis</span>()) <span class="comment">// undefined（没有指定 this 的初值）</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> getClassStaticThis = <span class="title class_">MyClass</span>.<span class="property">getStaticThis</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">MyClass</span>.<span class="title function_">getStaticThis</span>()) <span class="comment">// MyClass 类（指定了 this 的初值，在这里相当于 console.log(MyClass)）</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getClassStaticThis</span>()) <span class="comment">// undefined（没有指定 this 的初值）</span></span><br></pre></td></tr></table></figure>

<p>作为对比，将上面的代码使用传统的基于函数的语法实现，在<strong>非严格模式</strong>下，若 <code>this</code> 的初值没有指定，则会被置为全局对象。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">MyClass</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line"><span class="title class_">MyClass</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">getThis</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">MyClass</span>.<span class="property">getStaticThis</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123; <span class="comment">// 相当于静态方法</span></span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> obj = <span class="keyword">new</span> <span class="title class_">MyClass</span>()</span><br><span class="line"><span class="keyword">const</span> getObjThis = obj.<span class="property">getThis</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="title function_">getThis</span>()) <span class="comment">// obj 实例对象（指定了 this 的初值，在这里相当于 console.log(obj)）</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getObjThis</span>()) <span class="comment">// global object（没有指定 this 的初值）</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> getClassStaticThis = <span class="title class_">MyClass</span>.<span class="property">getStaticThis</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">MyClass</span>.<span class="title function_">getStaticThis</span>()) <span class="comment">// MyClass 函数（指定了 this 的初值，在这里相当于 console.log(MyClass)）</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getClassStaticThis</span>()) <span class="comment">// global object（没有指定 this 的初值）</span></span><br></pre></td></tr></table></figure>

<h2 id="生成器方法"><a href="#生成器方法" class="headerlink" title="生成器方法"></a>生成器方法</h2><p>生成器函数使用 <code>function*</code> 语法定义，例如 <code>function* anyGenerator() &#123;&#125;</code>。而在类中，使用了更简短的定义语法，应将符号 <code>*</code> 放在方法名的前面，例如 <code>*anyGenerator() &#123;&#125;</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Polygon</span> &#123; <span class="comment">// 定义五角形类</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">...sides</span>) &#123; <span class="comment">// 将传入的参数变成一个数组并执行构造方法</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">sides</span> = sides</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Method</span></span><br><span class="line">    *<span class="title function_">getSides</span>(<span class="params"></span>) &#123; <span class="comment">// 定义生成器方法</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> side <span class="keyword">of</span> <span class="variable language_">this</span>.<span class="property">sides</span>) &#123;</span><br><span class="line">            <span class="keyword">yield</span> side</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> pentagon = <span class="keyword">new</span> <span class="title class_">Polygon</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>([...pentagon.<span class="title function_">getSides</span>()]) <span class="comment">// [1,2,3,4,5]</span></span><br></pre></td></tr></table></figure>

<p>关于生成器的更多介绍可参考<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators">此页面</a>。</p>
<h2 id="箭头函数定义方法"><a href="#箭头函数定义方法" class="headerlink" title="箭头函数定义方法"></a>箭头函数定义方法</h2><p>类中还有另外一种常见的定义方法的方式：使用<strong>箭头函数</strong>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Rectangle</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">    calcArea = <span class="function">() =&gt;</span> &#123; <span class="comment">// 使用箭头函数定义原型方法</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">height</span> * <span class="variable language_">this</span>.<span class="property">width</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>特别的，箭头函数不会创建自己的 <code>this</code>，而是从自己的作用域链的上一层继承 <code>this</code>；子类继承父类的箭头函数定义的方法时，会出现属性遮蔽（Property Shadowing）的现象。对于后者，编写代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Father</span> &#123;</span><br><span class="line">    sayHello = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;I am your father.&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Chird</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Father</span> &#123;</span><br><span class="line">    <span class="title function_">sayHello</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>.<span class="title function_">sayHello</span>()</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;I am a chird.&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> c = <span class="keyword">new</span> <span class="title class_">Chird</span>()</span><br><span class="line">c.<span class="title function_">sayHello</span>() <span class="comment">// I am your father.</span></span><br></pre></td></tr></table></figure>

<p>上面的代码并没有像我们预想的那样，依次打印出 <code>I am your father.</code> 和 <code>I am a chird.</code>，而是只打印出了 <code>I am your father.</code>。</p>
<p>简单解释原因的话就是，箭头函数会挂到<strong>实例的属性</strong>上，而普通函数则是定义在<strong>原型链</strong>上。在 <code>Chird</code> 类中定义的 <code>sayHello()</code> 方法放到了原型链上，而从自己的父类 <code>Father</code> 继承的 <code>sayHello()</code> 方法挂载到了属性上。因此，当我们调用实例上的 <code>sayHello()</code> 方法时，优先从实例的属性上查找是否存在该方法（是的，在这里我们已经找到它了），如果存在则直接调用，如果不存在再在原型链上查找。</p>
<p>详细内容可以参考<a target="_blank" rel="noopener" href="https://github.com/dwqs/blog/issues/67#issue-327371697">这篇博客</a>。</p>
<p>在类中，对于直接使用 <code>=</code> 的声明，从本质上而言就是 <a target="_blank" rel="noopener" href="https://github.com/tc39/proposal-class-fields#field-declarations">Field Declarations</a> 的语法，相当于<strong>直接声明了一个实例的属性</strong>。在接下来的<a href="#%E5%AD%97%E6%AE%B5%E5%A3%B0%E6%98%8E">字段声明</a>小节中，也使用到了这个语法。</p>
<h2 id="字段声明"><a href="#字段声明" class="headerlink" title="字段声明"></a>字段声明</h2><blockquote>
<p>在目前（2021 年 5 月），公共和私有字段声明仍是 JavaScript 标准委员会 TC39 提出的<a target="_blank" rel="noopener" href="https://github.com/tc39/proposal-class-fields">实验性功能（第 3 阶段）</a>。浏览器中的支持是有限的，但是可以通过 Babel 等系统构建后使用此功能。</p>
</blockquote>
<h3 id="公有字段声明"><a href="#公有字段声明" class="headerlink" title="公有字段声明"></a>公有字段声明</h3><p>在类中可以声明公有字段，使得类定义具有自我记录性，且这些字段将始终存在。字段的声明可以设置初始值。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span> &#123;</span><br><span class="line">    x <span class="comment">// 公有字段 x</span></span><br><span class="line">    y = <span class="number">0</span> <span class="comment">// 公有字段 y，初始值为 0</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">x, y</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">x</span> = x</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">y</span> = y</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">position</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> [<span class="variable language_">this</span>.<span class="property">x</span>, <span class="variable language_">this</span>.<span class="property">y</span>]</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Point</span>(<span class="number">5</span>, <span class="number">10</span>).<span class="property">position</span>) <span class="comment">// [5, 10]</span></span><br></pre></td></tr></table></figure>

<h3 id="私有字段声明"><a href="#私有字段声明" class="headerlink" title="私有字段声明"></a>私有字段声明</h3><p>在声明的字段前面加上 <code>#</code> 表明为私有字段。私有字段同样可以设置初始值。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span> &#123;</span><br><span class="line">    #x <span class="comment">// 私有字段 x</span></span><br><span class="line">    #y = <span class="number">0</span> <span class="comment">// 私有字段 y，初始值为 0</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">x, y</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.#x = x</span><br><span class="line">        <span class="variable language_">this</span>.#y = y</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">position</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> [<span class="variable language_">this</span>.#x, <span class="variable language_">this</span>.#y]</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Point</span>(<span class="number">10</span>, <span class="number">5</span>).<span class="property">position</span>) <span class="comment">// [10, 5]</span></span><br></pre></td></tr></table></figure>

<p>与公有字段不同的是：</p>
<ul>
<li>不能从类外部引用私有字段。或私有字段在类外部不可见。</li>
<li>私有字段仅能在字段声明中预先定义。</li>
<li>在实例创建之后，不能再通过赋值来创建私有字段。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span> &#123;</span><br><span class="line">    name = <span class="string">&#x27;point&#x27;</span></span><br><span class="line">    #x</span><br><span class="line">    #y = <span class="number">0</span></span><br><span class="line">    <span class="comment">// #z // 假如不在这里显式声明 #z</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">x, y, z</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.#x = x</span><br><span class="line">        <span class="variable language_">this</span>.#y = y</span><br><span class="line">        <span class="comment">// this.#z = z // Uncaught SyntaxError: Private field &#x27;#z&#x27; must be declared in an enclosing class</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">position</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> [<span class="variable language_">this</span>.#x, <span class="variable language_">this</span>.#y]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">position3D</span>() &#123;</span><br><span class="line">        <span class="comment">// return [this.#x, this.#y, this.#z] // Uncaught SyntaxError: Private field &#x27;#z&#x27; must be declared in an enclosing class</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> p = <span class="keyword">new</span> <span class="title class_">Point</span>(<span class="number">10</span>, <span class="number">5</span>, <span class="number">15</span>)</span><br><span class="line">p.<span class="property">name</span> = <span class="string">&#x27;point3D&#x27;</span> <span class="comment">// 实例可以通过赋值修改公有字段</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(p.<span class="property">name</span>) <span class="comment">// point3D</span></span><br><span class="line">p.#x = <span class="number">20</span> <span class="comment">// 实例不可通过赋值修改私有字段，Uncaught SyntaxError: Private field &#x27;#x&#x27; must be declared in an enclosing class</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(p.#x) <span class="comment">// 实例不可在外部访问私有字段，Uncaught SyntaxError: Private field &#x27;#x&#x27; must be declared in an enclosing class</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们尝试在类中不显式声明私有字段 <code>#z</code> 的情况下，访问 <code>#z</code>，结果会抛出 <code>SyntaxError</code>。此外，我们尝试在实例中直接对私有字段 <code>#x</code> 进行赋值和获取操作，也会抛出 <code>SyntaxError</code>。</p>
<h2 id="使用-extends-拓展子类"><a href="#使用-extends-拓展子类" class="headerlink" title="使用 extends 拓展子类"></a>使用 <code>extends</code> 拓展子类</h2><p><code>extends</code> 可以用来创建子类，父类可以是自己定义的普通类，也可以是内建对象。对于后者，以继承内建的 <code>Date</code> 对象为例：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyDate</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Date</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">getFormattedDate</span>(<span class="params"></span>) &#123; <span class="comment">// 定义子类的方法，该方法可以获取格式化后的日期</span></span><br><span class="line">        <span class="keyword">const</span> months = [<span class="string">&#x27;Jan&#x27;</span>,<span class="string">&#x27;Feb&#x27;</span>,<span class="string">&#x27;Mar&#x27;</span>,<span class="string">&#x27;Apr&#x27;</span>,<span class="string">&#x27;May&#x27;</span>,<span class="string">&#x27;Jun&#x27;</span>,<span class="string">&#x27;Jul&#x27;</span>,<span class="string">&#x27;Aug&#x27;</span>,<span class="string">&#x27;Sep&#x27;</span>,<span class="string">&#x27;Oct&#x27;</span>,<span class="string">&#x27;Nov&#x27;</span>,<span class="string">&#x27;Dec&#x27;</span>]</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">getDate</span>() + <span class="string">&#x27; - &#x27;</span> + months[<span class="variable language_">this</span>.<span class="title function_">getMonth</span>()] + <span class="string">&#x27; - &#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">getFullYear</span>()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">MyDate</span>().<span class="title function_">getFormattedDate</span>()) <span class="comment">// 20 - May - 2021</span></span><br></pre></td></tr></table></figure>

<p>类不过是一种语法糖，因此我们也可以用 <code>extends</code> 来继承传统的基于函数的“类”：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Animal</span> (name) &#123; <span class="comment">// 定义 Animal “类”</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Animal</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">speak</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&#x27; makes a noise.&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Animal</span> &#123; <span class="comment">// 使用 extends 拓展 Animal “类”</span></span><br><span class="line">    <span class="title function_">speak</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>.<span class="title function_">speak</span>()</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&#x27; barks.&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> d = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&#x27;Mitzie&#x27;</span>)</span><br><span class="line">d.<span class="title function_">speak</span>()</span><br><span class="line"><span class="comment">// Mitzie makes a noise.</span></span><br><span class="line"><span class="comment">// Mitzie barks.</span></span><br></pre></td></tr></table></figure>

<p>对于<strong>不可构造</strong>的常规对象，要实现继承的话，可以使用 <code>Object.setPrototypeOf()</code> 方法，它可以设置一个指定对象的原型到另一个对象：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">Animal</span> = &#123; <span class="comment">// 定义 Animal 对象</span></span><br><span class="line">    <span class="title function_">speak</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&#x27; makes a noise.&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">name</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">speak</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>.<span class="title function_">speak</span>()</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&#x27; barks.&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">setPrototypeOf</span>(<span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span>, <span class="title class_">Animal</span>) <span class="comment">// 如果不这样做，在调用 speak 时会返回 TypeError</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> d = <span class="keyword">new</span> <span class="title class_">Dog</span>(<span class="string">&#x27;Mitzie&#x27;</span>)</span><br><span class="line">d.<span class="title function_">speak</span>()</span><br><span class="line"><span class="comment">// Mitzie makes a noise.</span></span><br><span class="line"><span class="comment">// Mitzie barks.</span></span><br></pre></td></tr></table></figure>

<p>出于性能考量，应避免使用 <code>Object.setPrototypeOf()</code> 方法来实现继承，在<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf">这里</a>了解它的更多。</p>
<h2 id="使用-super-调用超类"><a href="#使用-super-调用超类" class="headerlink" title="使用 super 调用超类"></a>使用 <code>super</code> 调用超类</h2><p>使用 <code>super</code> 关键字可以调用对象的父对象上的函数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Cat</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">name</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">speak</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;<span class="variable language_">this</span>.name&#125;</span>: meo~~!`</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Lion</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Cat</span> &#123;</span><br><span class="line">    <span class="title function_">speak</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>.<span class="title function_">speak</span>() <span class="comment">// 调用 Cat 对象的 speak 方法</span></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;<span class="variable language_">this</span>.name&#125;</span>: roars!!!`</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> l = <span class="keyword">new</span> <span class="title class_">Lion</span>(<span class="string">&#x27;Li&#x27;</span>)</span><br><span class="line">l.<span class="title function_">speak</span>()</span><br><span class="line"><span class="comment">// Li: meo~~!</span></span><br><span class="line"><span class="comment">// Li: roars!!!</span></span><br></pre></td></tr></table></figure>

<p>假如我们将上面代码中 <code>Lion</code> 类里的 <code>speak()</code> 方法删去，那么打印的结果是 <code>Li: meo~~!</code>。如果认真学到这里的话，原因想必也已经了然于胸：子类继承了父类的属性和方法。那么当子类定义了与父类相同名字的方法时，根据原型链上的调用规则，会调用子类定义的方法。这就是为什么我们需要 <code>super</code> 关键字的原因之一，方法名相同的情况下，在子类方法中我们仍可以调用父类的方法。</p>
<p>在<strong>构造函数</strong>中，<code>super()</code> 需要在使用 <code>this</code> 前调用：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Rectangle</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">height, width</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_name</span> = <span class="string">&#x27;Rectangle&#x27;</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_height</span> = height</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_width</span> = width</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">name</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">`Hi, I am a <span class="subst">$&#123;<span class="variable language_">this</span>._name&#125;</span>.`</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">area</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_height</span> * <span class="variable language_">this</span>.<span class="property">_width</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Square</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Rectangle</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">length</span>) &#123;</span><br><span class="line">        <span class="comment">// this._height = length // Must call super constructor in derived class before accessing &#x27;this&#x27; or returning from derived constructor</span></span><br><span class="line">        <span class="variable language_">super</span>(length, length) <span class="comment">// 调用 Rectangle 的构造函数，length 分别作 height 和 width</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_name</span> = <span class="string">&#x27;Square&#x27;</span> <span class="comment">// 修改 name 属性为 Square</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> s = <span class="keyword">new</span> <span class="title class_">Square</span>(<span class="number">15</span>)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="property">name</span>) <span class="comment">// Hi, I am a Square.</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(s.<span class="property">area</span>) <span class="comment">// 225</span></span><br></pre></td></tr></table></figure>

<p><code>super</code> 也可以用来调用父类的静态方法：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Rectangle</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">height, width</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_height</span> = height</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_width</span> = width</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> <span class="title function_">help</span>(<span class="params"></span>) &#123; <span class="comment">// 父类的静态方法</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;I have 4 sides.&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Square</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Rectangle</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">length</span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>(length, length)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">static</span> <span class="title function_">help</span>(<span class="params"></span>) &#123; <span class="comment">// 子类的静态方法，使用 super 调用父类的 help 方法</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">super</span>.<span class="title function_">help</span>() + <span class="string">&#x27; They are all equal.&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Square</span>.<span class="title function_">help</span>()) <span class="comment">// I have 4 sides. They are all equal.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 假如只去除子类 help 方法前面的 static 关键字</span></span><br><span class="line"><span class="comment">// console.log(new Square(10).help()) // Uncaught TypeError: (intermediate value).help is not a function</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 假如只去除父类 help 方法前面的 static 关键字</span></span><br><span class="line"><span class="comment">// console.log(Square.help()) // Uncaught TypeError: (intermediate value).help is not a function</span></span><br></pre></td></tr></table></figure>

<p>在上面的代码中，<code>Square</code> 中的静态方法 <code>help()</code> 调用了父类的静态方法。静态方法中的 <code>super</code> 只能调用父类的静态方法，假如我们去除子类或父类方法前面的 <code>static</code> 关键字，会发生报错。</p>
<p>在本章节的例子中，似乎子类方法中的 <code>super</code> 都调用了父类中与之同名的方法，但实际上并没有这个限制，在编写的时候可以根据实际的需求自行调整命名或调用其它父类方法。</p>
<p>在<a href="#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E6%96%B9%E6%B3%95">箭头函数的使用</a>章节的例子中，既然箭头函数定义的方法挂载到了实例的属性上，那么还能用 <code>super</code> 来调用吗？答案是否定的。JavaScript 没能在父对象的原型链上找到这个方法，于是什么也没有发生。</p>
<p>更多补充可以查阅 MDN 上<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super">关于 <code>super</code> 的介绍</a>。</p>
<h2 id="使用-Symbol-species-覆盖构造函数"><a href="#使用-Symbol-species-覆盖构造函数" class="headerlink" title="使用 Symbol.species 覆盖构造函数"></a>使用 <code>Symbol.species</code> 覆盖构造函数</h2><p><code>Symbol.species</code> 访问器属性允许子类覆盖对象的默认构造函数。</p>
<p>读着很拗口，那就看两个实际的例子。当使用 <code>map()</code> 这样的方法会返回默认的构造函数，我们可能想在对拓展的数组类 <code>MyArray</code> 执行操作时返回 <code>Array</code> 对象，那么可以这样编写代码：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyArray</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Array</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> get [<span class="title class_">Symbol</span>.<span class="property">species</span>]() &#123; <span class="comment">// 设置 getter，当获取 MyArray 类的构造函数时，返回 Array 类的构造函数</span></span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Array</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> a = <span class="keyword">new</span> <span class="title class_">MyArray</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line"><span class="keyword">const</span> mapped = a.<span class="title function_">map</span>(<span class="function"><span class="params">x</span> =&gt;</span> x * x)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(mapped <span class="keyword">instanceof</span> <span class="title class_">MyArray</span>); <span class="comment">// false</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(mapped <span class="keyword">instanceof</span> <span class="title class_">Array</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>

<p>又例如，我们拓展 <code>Promise</code> 类为 <code>TimeoutPromise</code> 类，但我们不希望某一个超时的 Promise 请求影响整个 Promise 链，就可以使用 <code>Symbol.species</code> 来告诉 <code>TimeoutPromise</code> 类返回一个 <code>Promise</code> 对象，方便我们执行异常处理操作：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">TimeoutPromise</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Promise</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> get [<span class="title class_">Symbol</span>.<span class="property">species</span>]() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Promise</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>Symbol.species</code> 允许自定义返回的类，不一定是子类继承实现的类。</p>
<p><code>Symbol.species</code> 帮助我们在处理子类实例时，能够有一套标准的操作流程，方便了开发，在某些场景十分实用。</p>
<h2 id="使用-Mix-ins-实现多重继承"><a href="#使用-Mix-ins-实现多重继承" class="headerlink" title="使用 Mix-ins 实现多重继承"></a>使用 Mix-ins 实现多重继承</h2><p>在 ECMAScript 中，一个类只能有一个单超类，因此想通过工具类的方法实现多重继承行为是不可能的。为了实现多重继承，我们可以使用 Mixin 的方法。</p>
<p>什么是 Mixin？简单来说，Mixin 也是一个类，包括了一些方法，这些方法可以被其它类使用。但在其它类中使用这些方法<strong>不需要继承</strong> Mixin。举一个简单的例子：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> sayHiMixin = &#123; <span class="comment">// Mixin</span></span><br><span class="line">    <span class="comment">// Methods that useful</span></span><br><span class="line">    <span class="title function_">sayHi</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="title function_">alert</span>(<span class="string">`Hello, <span class="subst">$&#123;<span class="variable language_">this</span>.name&#125;</span>`</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="title function_">sayBye</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="title function_">alert</span>(<span class="string">`Bye, <span class="subst">$&#123;<span class="variable language_">this</span>.name&#125;</span>`</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">User</span> &#123; <span class="comment">// Class</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">name</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span> = name</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">assign</span>(<span class="title class_">User</span>.<span class="property"><span class="keyword">prototype</span></span>, sayHiMixin) <span class="comment">// 将 Mixin 中的方法复制到 Class 类中</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">User</span>(<span class="string">&#x27;Dude&#x27;</span>).<span class="title function_">sayHi</span>() <span class="comment">// Hello, Dude!</span></span><br></pre></td></tr></table></figure>

<p>我们又知道，创建类的<a href="#%E5%AE%9A%E4%B9%89%E7%B1%BB">两种声明方式</a>是等价的：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Mixin1</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 等价于</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Mixin2</span> = <span class="keyword">class</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>其中，第二种方式，或者说使用类表达式声明类的方式，允许我们<strong>动态生成自定义的类</strong>。根据这个特性，我们就可以编写 Mixin 代码来实现多重继承了：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span> &#123; <span class="comment">// 共同工具类</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CatMixin</span> = <span class="function">(<span class="params">superClass</span>) =&gt;</span> <span class="keyword">class</span> <span class="title class_">extends</span> superClass &#123; <span class="comment">// 猫猫工具类</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">DogMixin</span> = <span class="function">(<span class="params">superClass</span>) =&gt;</span> <span class="keyword">class</span> <span class="title class_">extends</span> superClass &#123; <span class="comment">// 狗狗工具类</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyMixin</span> <span class="keyword">extends</span> <span class="title class_ inherited__">CatMixin</span>(<span class="title class_">DogMixin</span>(<span class="title class_">Animal</span>)) &#123; <span class="comment">// 实现多重继承</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上面的代码中，我们首先定义了一个通用的工具类 <code>Animal</code>，其它 Mixin 类可能会用到这个工具类。接着我们定义了猫猫和狗狗使用的工具类 <code>CatMixin</code> 与 <code>DogMixin</code> 的创建规则，它们将传入的参数作为自己的父类，并创建一个新的类。最后，我们定义了想要的 <code>MyMixin</code> 类，它继承了 <code>CatMixin(DogMixin(Animal))</code> 类。从实现的角度来看，<strong>相当于</strong>执行了下面的操作：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">DogMixin</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Animal</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CatMixin</span> <span class="keyword">extends</span> <span class="title class_ inherited__">DogMixin</span> &#123; <span class="comment">// 这显然是不合理的，猫猫工具类怎么能继承狗狗工具类</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyMixin</span> <span class="keyword">extends</span> <span class="title class_ inherited__">CatMixin</span> &#123;</span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实际上，我们并没有让 <code>CatMixin</code> 类去继承 <code>DogMixin</code> 类，而是使用了 Mixin 的思想，让 <code>MyMixin</code> 继承了我们基于类表达式创建的一个新的类，实现了多重继承。</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p>本博文仅且记录了 JavaScript 中类在语法上的知识和使用，和少量的实现原理。关于底层的具体实现，就放到以后再深入探讨学习吧。</p>
<h3 id="技术博文"><a href="#技术博文" class="headerlink" title="技术博文"></a>技术博文</h3><ul>
<li><a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1700017">JavaScript或ES6如何实现多继承总结【Mixin混合继承模式】</a>, 2020-09-18</li>
<li><a target="_blank" rel="noopener" href="https://github.com/dwqs/blog/issues/67">ES6 Class Methods 定义方式的差异</a>, 2018-06-25</li>
<li><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000007356931">[学习es6]setter/getter探究</a>, 2016-11-02</li>
<li><a target="_blank" rel="noopener" href="https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/#symbolspecies">Metaprogramming in ES6: Symbols and why they’re awesome</a>, 2015-06-18</li>
</ul>
<h3 id="其它资料"><a href="#其它资料" class="headerlink" title="其它资料"></a>其它资料</h3><p>主要参考了 MDN 上关于类和相关内容的<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">描述</a>。</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://javascript.info/mixins">Mixins - JAVASCRIPT.INFO</a></li>
</ul>

    </article>
    <!-- license -->
    
        <div class="license-wrapper">
            <p>原文作者：<a href="https://LolipopJ.github.io">Lolipop</a>
            <p>原文链接：<a href="https://lolipopj.github.io/2021/05/19/js-use-class/">https://lolipopj.github.io/2021/05/19/js-use-class/</a>
            <p>发表日期：<a href="https://lolipopj.github.io/2021/05/19/js-use-class/">May 19th 2021, 4:00:00 pm</a>
            <p>更新日期：<a href="https://lolipopj.github.io/2021/05/19/js-use-class/">May 19th 2021, 4:00:00 pm</a>
            <p>版权声明：本文采用<a rel="license noopener" target="_blank" href="http://creativecommons.org/licenses/by-nc/4.0/">知识共享署名-非商业性使用 4.0 国际许可协议</a>进行许可</p>
        </div>
    
    <!-- paginator -->
    <ul class="post-paginator">
        <li class="next">
            
                <div class="nextSlogan">Next Post</div>
                <a href="/2021/06/03/euler-install-mysql/" title="在 Euler 系统上离线安装 MySQL 5.7">
                    <div class="nextTitle">在 Euler 系统上离线安装 MySQL 5.7</div>
                </a>
            
        </li>
        <li class="previous">
            
                <div class="prevSlogan">Previous Post</div>
                <a href="/2021/05/17/js-closure/" title="漫谈 JavsScript 闭包">
                    <div class="prevTitle">漫谈 JavsScript 闭包</div>
                </a>
            
        </li>
    </ul>
    <!-- comment -->
    
        <div class="post-comment">
            <!-- 来必力 City 版安装代码 -->


            

            

            
    <div id="gitalk-container"></div>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.css">
    <script src="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.min.js"></script>
    <script>
        let idOption = 'Wed May 19 2021 16:00:00 GMT+0000'
        
            idOption = location.pathname
        
        const gitalk = new Gitalk({
            clientID: '3e27d4e7935138a80cd8',
            clientSecret: 'cd3eda2bf0740e7a51b8b611ade908eb95590e45',
            repo: 'LolipopJ.github.io',
            owner: 'LolipopJ',
            admin: ["LolipopJ"],
            id: idOption,
            distractionFreeMode: false,
            createIssueManually: false,
        })
        gitalk.render('gitalk-container')
    </script>
    <noscript>为正常使用 Gitalk 评论功能，您需要激活 JavaScript</noscript>


            <!-- utteranc评论 -->


            <!-- partial('_partial/comment/changyan') -->
            <!--PC版-->


            
            

            

        </div>
    
    <!-- timeliness note -->
    <!-- idea from: https://hexo.fluid-dev.com/posts/hexo-injector/#%E6%96%87%E7%AB%A0%E6%97%B6%E6%95%88%E6%80%A7%E6%8F%90%E7%A4%BA -->
    
    <!-- Mathjax -->
    
</main>

                <!-- profile -->
                
            </div>
            <footer class="footer footer-unloaded">
    <!-- social  -->
    
        <div class="social">
            
    
        
            
                <a href="mailto:lolipop0703@qq.com" class="iconfont-archer email" title=email ></a>
            
        
    
        
            
                <a href="//github.com/LolipopJ" class="iconfont-archer github" target="_blank" title=github></a>
            
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
            
                <a href="https://twitter.com/Lolipop_0703" class="iconfont-archer twitter" target="_blank" title=twitter></a>
            
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
    
        
            
                <a href="/atom.xml" class="iconfont-archer rss" target="_blank" title=rss></a>
            
        
    


        </div>
    
    <!-- powered by Hexo  -->
    <div class="copyright">
        <span id="hexo-power">Powered by <a href="https://hexo.io/" target="_blank">Hexo</a></span><span class="iconfont-archer power">&#xe635;</span><span id="theme-info">theme <a href="https://github.com/fi3ework/hexo-theme-archer" target="_blank">Archer</a></span>
    </div>
    <!-- website approve for Chinese user -->
    
        <div class="website-approve">
            
                <span id="icp-approve" class="icp-approve">
                    <a href="https://beian.miit.gov.cn/" target="_blank">蜀ICP备 2021015698号</a>
                </span>
            
            
                
                <img class="beian-img" src="/assets/beian.png" />
                <span id="beian-approve" class="beian-approve">
                    <a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=51010802001109" target="_blank">京公网安备 51010802001109号</a>
                </span>
            
        </div>
    
    <!-- 不蒜子  -->
    
        <div class="busuanzi-container">
            
             
                <span id="busuanzi_container_site_pv">PV: <span id="busuanzi_value_site_pv"></span> :)</span>
            
        </div>
    	
</footer>

        </div>
        <!-- toc -->
        
            <div class="toc-wrapper toc-wrapper-loding" style=







    top:50vh;

>
                <div class="toc-catalog">
                    <span class="iconfont-archer catalog-icon">&#xe613;</span><span>CATALOG</span>
                </div>
                <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%9A%E4%B9%89%E7%B1%BB"><span class="toc-number">1.</span> <span class="toc-text">定义类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><span class="toc-number">2.</span> <span class="toc-text">构造函数</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8E%9F%E5%9E%8B%E6%96%B9%E6%B3%95"><span class="toc-number">3.</span> <span class="toc-text">原型方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E5%92%8C%E5%B1%9E%E6%80%A7"><span class="toc-number">4.</span> <span class="toc-text">静态方法和属性</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8E%9F%E5%9E%8B%E6%96%B9%E6%B3%95%E5%92%8C%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E4%B8%AD%E7%9A%84-this"><span class="toc-number">5.</span> <span class="toc-text">原型方法和静态方法中的 this</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%9F%E6%88%90%E5%99%A8%E6%96%B9%E6%B3%95"><span class="toc-number">6.</span> <span class="toc-text">生成器方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E6%96%B9%E6%B3%95"><span class="toc-number">7.</span> <span class="toc-text">箭头函数定义方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AD%97%E6%AE%B5%E5%A3%B0%E6%98%8E"><span class="toc-number">8.</span> <span class="toc-text">字段声明</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%AC%E6%9C%89%E5%AD%97%E6%AE%B5%E5%A3%B0%E6%98%8E"><span class="toc-number">8.1.</span> <span class="toc-text">公有字段声明</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%A7%81%E6%9C%89%E5%AD%97%E6%AE%B5%E5%A3%B0%E6%98%8E"><span class="toc-number">8.2.</span> <span class="toc-text">私有字段声明</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-extends-%E6%8B%93%E5%B1%95%E5%AD%90%E7%B1%BB"><span class="toc-number">9.</span> <span class="toc-text">使用 extends 拓展子类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-super-%E8%B0%83%E7%94%A8%E8%B6%85%E7%B1%BB"><span class="toc-number">10.</span> <span class="toc-text">使用 super 调用超类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-Symbol-species-%E8%A6%86%E7%9B%96%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><span class="toc-number">11.</span> <span class="toc-text">使用 Symbol.species 覆盖构造函数</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8-Mix-ins-%E5%AE%9E%E7%8E%B0%E5%A4%9A%E9%87%8D%E7%BB%A7%E6%89%BF"><span class="toc-number">12.</span> <span class="toc-text">使用 Mix-ins 实现多重继承</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"><span class="toc-number">13.</span> <span class="toc-text">参考资料</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%8A%80%E6%9C%AF%E5%8D%9A%E6%96%87"><span class="toc-number">13.1.</span> <span class="toc-text">技术博文</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B6%E5%AE%83%E8%B5%84%E6%96%99"><span class="toc-number">13.2.</span> <span class="toc-text">其它资料</span></a></li></ol></li></ol>
            </div>
        
        <!-- sidebar -->
        <div class="sidebar sidebar-hide">
    <ul class="sidebar-tabs sidebar-tabs-active-0">
        <li class="sidebar-tab-archives"><span class="iconfont-archer">&#xe67d;</span><span class="tab-name">Archive</span></li>
        <li class="sidebar-tab-tags"><span class="iconfont-archer">&#xe61b;</span><span class="tab-name">Tag</span></li>
        <li class="sidebar-tab-categories"><span class="iconfont-archer">&#xe666;</span><span class="tab-name">Cate</span></li>
    </ul>
    <div class="sidebar-content sidebar-content-show-archive">
        <div class="sidebar-panel-archives">
    <!-- 在 ejs 中将 archive 按照时间排序 -->
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    
    
    
    
    <div class="total-and-search">
        <div class="total-archive">
        Total : 31
        </div>
        <!-- search  -->
        
            <div class="site-search site-search-loading popup-trigger">
                <span class="iconfont-archer search-icon">&#xe627;</span>
            </div>
        
    </div>
    
    <div class="post-archive">
    
        
            
            
            <div class="archive-year"> 2022 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/12</span>
            <a class="archive-post-title" href="/2022/02/11/connect-with-pgsql/">连接到 Windows 端的 PostgreSQL 数据库</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">01/13</span>
            <a class="archive-post-title" href="/2022/01/12/random-get-me-a-picture/">这位客官，要来一张我珍藏许久的图片吗</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">01/09</span>
            <a class="archive-post-title" href="/2022/01/08/start-telegram-bot/">从零开始使用 Telegram Bot</a>
        </li>
    
        
            
            
                
                </ul>
            
            <div class="archive-year"> 2021 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">08/19</span>
            <a class="archive-post-title" href="/2021/08/18/build-my-resume/">把自己的简历做成 Web 页面</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">08/13</span>
            <a class="archive-post-title" href="/2021/08/12/github-jsdelivr-hold-image/">使用 jsDelivr 加速 Github 仓库搭建自己的图床服务</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">08/07</span>
            <a class="archive-post-title" href="/2021/08/06/editorconfig-prettier/">使用 EditorConfig 和 Prettier 优雅地配置 VSCode 代码格式化</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">07/10</span>
            <a class="archive-post-title" href="/2021/07/09/switch-travis-to-github-workflow/">更换持续集成工具，从 Travis 到 Github Actions</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">07/08</span>
            <a class="archive-post-title" href="/2021/07/07/browser-behind-visit-url/">在浏览器中输入 URL 到显示网页，背后发生了什么</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/26</span>
            <a class="archive-post-title" href="/2021/06/25/web-font-for-hexo-theme-archer/">为 Archer 主题更换字体</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/25</span>
            <a class="archive-post-title" href="/2021/06/24/website-deployment-docker-nginx/">使用基于 Docker 的 Nginx 部署静态网页项目</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/09</span>
            <a class="archive-post-title" href="/2021/06/08/linux-project-v/">在 Linux 系统下启用 Project-V</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">06/04</span>
            <a class="archive-post-title" href="/2021/06/03/euler-install-mysql/">在 Euler 系统上离线安装 MySQL 5.7</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/20</span>
            <a class="archive-post-title" href="/2021/05/19/js-use-class/">漫谈 JavsScript 类（Class）的使用</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/18</span>
            <a class="archive-post-title" href="/2021/05/17/js-closure/">漫谈 JavsScript 闭包</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/11</span>
            <a class="archive-post-title" href="/2021/05/10/js-hoisting/">JavsScript 变量提升和函数提升</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">05/08</span>
            <a class="archive-post-title" href="/2021/05/07/js-debounce-throttle/">函数防抖和节流，以及在 Vue 中的运用</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">04/26</span>
            <a class="archive-post-title" href="/2021/04/25/windows-install-grpc/">Windows 系统编译安装基于 C++ 的 gRPC</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">04/22</span>
            <a class="archive-post-title" href="/2021/04/21/linux-docker-install-grpc/">Linux 系统编译安装基于 C++ 的 gRPC</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">04/20</span>
            <a class="archive-post-title" href="/2021/04/19/linux-docker-gcc-update/">Linux 容器更新或降级 GCC 版本</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/29</span>
            <a class="archive-post-title" href="/2021/03/28/protobuf-learning/">Protobuf 学习笔记</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/17</span>
            <a class="archive-post-title" href="/2021/03/16/amap-import-vue/">在 Nuxt.js 中引入高德地图并实现定位及逆地理编码</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/16</span>
            <a class="archive-post-title" href="/2021/03/15/tencent-map-api-get-current-location/">使用腾讯位置服务进行 Web 前端定位</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/10</span>
            <a class="archive-post-title" href="/2021/03/09/xxx-is-not-a-symbolic-link/">提示 *** is not a symbolic link 解决方案</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">03/03</span>
            <a class="archive-post-title" href="/2021/03/02/nodejs-eslint-prettier/">Nuxt 项目配置 ESLint 和 Prettier 检查并规范代码质量与格式</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/23</span>
            <a class="archive-post-title" href="/2021/02/22/write-md-parser/">Webpack 读取本地 Markdown 文件并进行预处理</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/21</span>
            <a class="archive-post-title" href="/2021/02/20/tg-mtproto-one-click/">一键安装并配置 MTProto Proxy 代理 Telegram</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">02/19</span>
            <a class="archive-post-title" href="/2021/02/18/hexo-github-actions-ci-cd/">使用 Github Actions 持续集成与部署 Hexo 博客</a>
        </li>
    
        
            
            
                
                </ul>
            
            <div class="archive-year"> 2020 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">12/29</span>
            <a class="archive-post-title" href="/2020/12/28/ISO-IEC-IEEE-42010-des/">IEEE 1471（ISO/IEC/IEEE 42010）架构描述方法</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">09/28</span>
            <a class="archive-post-title" href="/2020/09/27/pytorch-install-windows-10/">PyTorch 在 Windows 10 系统下的环境配置及安装</a>
        </li>
    
        
            
            
                
                </ul>
            
            <div class="archive-year"> 2019 </div>
            <ul class="year-list">
            
        
        <li class="archive-post-item">
            <span class="archive-post-date">12/27</span>
            <a class="archive-post-title" href="/2019/12/26/archer-theme-update-log/">基于 Archer 主题的博客开发</a>
        </li>
    
        
        <li class="archive-post-item">
            <span class="archive-post-date">12/27</span>
            <a class="archive-post-title" href="/2019/12/26/hello-hexo-world/">Hello Hexo World</a>
        </li>
    
    </div>
</div>

        <div class="sidebar-panel-tags">
    <div class="sidebar-tags-name">
        
            <span class="sidebar-tag-name" data-tags="开发日志">
                <span class="iconfont-archer">&#xe606;</span>
                开发日志
            </span>
        
            <span class="sidebar-tag-name" data-tags="Vue-2">
                <span class="iconfont-archer">&#xe606;</span>
                Vue-2
            </span>
        
            <span class="sidebar-tag-name" data-tags="软件体系架构设计">
                <span class="iconfont-archer">&#xe606;</span>
                软件体系架构设计
            </span>
        
            <span class="sidebar-tag-name" data-tags="JavaScript">
                <span class="iconfont-archer">&#xe606;</span>
                JavaScript
            </span>
        
            <span class="sidebar-tag-name" data-tags="Node">
                <span class="iconfont-archer">&#xe606;</span>
                Node
            </span>
        
            <span class="sidebar-tag-name" data-tags="Nuxt">
                <span class="iconfont-archer">&#xe606;</span>
                Nuxt
            </span>
        
            <span class="sidebar-tag-name" data-tags="Promise">
                <span class="iconfont-archer">&#xe606;</span>
                Promise
            </span>
        
            <span class="sidebar-tag-name" data-tags="博客开发">
                <span class="iconfont-archer">&#xe606;</span>
                博客开发
            </span>
        
            <span class="sidebar-tag-name" data-tags="Hexo">
                <span class="iconfont-archer">&#xe606;</span>
                Hexo
            </span>
        
            <span class="sidebar-tag-name" data-tags="hexo-theme-archer">
                <span class="iconfont-archer">&#xe606;</span>
                hexo-theme-archer
            </span>
        
            <span class="sidebar-tag-name" data-tags="计算机网络">
                <span class="iconfont-archer">&#xe606;</span>
                计算机网络
            </span>
        
            <span class="sidebar-tag-name" data-tags="网络安全">
                <span class="iconfont-archer">&#xe606;</span>
                网络安全
            </span>
        
            <span class="sidebar-tag-name" data-tags="密码学">
                <span class="iconfont-archer">&#xe606;</span>
                密码学
            </span>
        
            <span class="sidebar-tag-name" data-tags="resume">
                <span class="iconfont-archer">&#xe606;</span>
                resume
            </span>
        
            <span class="sidebar-tag-name" data-tags="CSS">
                <span class="iconfont-archer">&#xe606;</span>
                CSS
            </span>
        
            <span class="sidebar-tag-name" data-tags="Github-actions">
                <span class="iconfont-archer">&#xe606;</span>
                Github-actions
            </span>
        
            <span class="sidebar-tag-name" data-tags="rxjs">
                <span class="iconfont-archer">&#xe606;</span>
                rxjs
            </span>
        
            <span class="sidebar-tag-name" data-tags="PostgreSQL">
                <span class="iconfont-archer">&#xe606;</span>
                PostgreSQL
            </span>
        
            <span class="sidebar-tag-name" data-tags="Windows">
                <span class="iconfont-archer">&#xe606;</span>
                Windows
            </span>
        
            <span class="sidebar-tag-name" data-tags="EditorConfig">
                <span class="iconfont-archer">&#xe606;</span>
                EditorConfig
            </span>
        
            <span class="sidebar-tag-name" data-tags="Prettier">
                <span class="iconfont-archer">&#xe606;</span>
                Prettier
            </span>
        
            <span class="sidebar-tag-name" data-tags="VSCode">
                <span class="iconfont-archer">&#xe606;</span>
                VSCode
            </span>
        
            <span class="sidebar-tag-name" data-tags="Linux">
                <span class="iconfont-archer">&#xe606;</span>
                Linux
            </span>
        
            <span class="sidebar-tag-name" data-tags="MySQL">
                <span class="iconfont-archer">&#xe606;</span>
                MySQL
            </span>
        
            <span class="sidebar-tag-name" data-tags="Github">
                <span class="iconfont-archer">&#xe606;</span>
                Github
            </span>
        
            <span class="sidebar-tag-name" data-tags="jsDiliver">
                <span class="iconfont-archer">&#xe606;</span>
                jsDiliver
            </span>
        
            <span class="sidebar-tag-name" data-tags="ES6">
                <span class="iconfont-archer">&#xe606;</span>
                ES6
            </span>
        
            <span class="sidebar-tag-name" data-tags="GCC">
                <span class="iconfont-archer">&#xe606;</span>
                GCC
            </span>
        
            <span class="sidebar-tag-name" data-tags="Docker">
                <span class="iconfont-archer">&#xe606;</span>
                Docker
            </span>
        
            <span class="sidebar-tag-name" data-tags="CPP">
                <span class="iconfont-archer">&#xe606;</span>
                CPP
            </span>
        
            <span class="sidebar-tag-name" data-tags="gRPC">
                <span class="iconfont-archer">&#xe606;</span>
                gRPC
            </span>
        
            <span class="sidebar-tag-name" data-tags="ESLint">
                <span class="iconfont-archer">&#xe606;</span>
                ESLint
            </span>
        
            <span class="sidebar-tag-name" data-tags="Protobuf">
                <span class="iconfont-archer">&#xe606;</span>
                Protobuf
            </span>
        
            <span class="sidebar-tag-name" data-tags="机器学习">
                <span class="iconfont-archer">&#xe606;</span>
                机器学习
            </span>
        
            <span class="sidebar-tag-name" data-tags="PyTorch">
                <span class="iconfont-archer">&#xe606;</span>
                PyTorch
            </span>
        
            <span class="sidebar-tag-name" data-tags="Telegram">
                <span class="iconfont-archer">&#xe606;</span>
                Telegram
            </span>
        
            <span class="sidebar-tag-name" data-tags="Bot">
                <span class="iconfont-archer">&#xe606;</span>
                Bot
            </span>
        
            <span class="sidebar-tag-name" data-tags="Koa">
                <span class="iconfont-archer">&#xe606;</span>
                Koa
            </span>
        
            <span class="sidebar-tag-name" data-tags="Sequelize">
                <span class="iconfont-archer">&#xe606;</span>
                Sequelize
            </span>
        
            <span class="sidebar-tag-name" data-tags="Travis">
                <span class="iconfont-archer">&#xe606;</span>
                Travis
            </span>
        
            <span class="sidebar-tag-name" data-tags="MTProto">
                <span class="iconfont-archer">&#xe606;</span>
                MTProto
            </span>
        
            <span class="sidebar-tag-name" data-tags="Nginx">
                <span class="iconfont-archer">&#xe606;</span>
                Nginx
            </span>
        
            <span class="sidebar-tag-name" data-tags="Markdown">
                <span class="iconfont-archer">&#xe606;</span>
                Markdown
            </span>
        
            <span class="sidebar-tag-name" data-tags="Webpack">
                <span class="iconfont-archer">&#xe606;</span>
                Webpack
            </span>
        
    </div>
    <div class="iconfont-archer sidebar-tags-empty">&#xe678;</div>
    <div class="tag-load-fail" style="display: none; color: #ccc; font-size: 0.6rem;">
        缺失模块，请参考主题文档进行安装配置：https://github.com/fi3ework/hexo-theme-archer#%E5%AE%89%E8%A3%85%E4%B8%BB%E9%A2%98
    </div> 
    <div class="sidebar-tags-list"></div>
</div>

        <div class="sidebar-panel-categories">
    <div class="sidebar-categories-name">
    
        <span class="sidebar-category-name" data-categories="学习琐事">
            <span class="iconfont-archer">&#xe60a;</span>
            学习琐事
        </span>
    
        <span class="sidebar-category-name" data-categories="前端开发">
            <span class="iconfont-archer">&#xe60a;</span>
            前端开发
        </span>
    
        <span class="sidebar-category-name" data-categories="后端开发">
            <span class="iconfont-archer">&#xe60a;</span>
            后端开发
        </span>
    
        <span class="sidebar-category-name" data-categories="技术琐事">
            <span class="iconfont-archer">&#xe60a;</span>
            技术琐事
        </span>
    
    </div>
    <div class="iconfont-archer sidebar-categories-empty">&#xe678;</div>
    <div class="sidebar-categories-list"></div>
</div>

    </div>
</div>

        <!-- site-meta -->
        <script>
    var siteMetaRoot = "/"
    if (siteMetaRoot === "undefined") {
        siteMetaRoot = '/'
    }
    var siteMeta = {
        url: "https://LolipopJ.github.io",
        root: siteMetaRoot,
        author: "Lolipop"
    }
</script>

        <!-- import experimental options here -->
        <!-- Custom Font -->

    <!-- Check browser compatibility of CSS variables -->
    <script>
        if (browserSupportCSSVariables === undefined) {
            var browserSupportCSSVariables = window.CSS && window.CSS.supports && window.CSS.supports('--a', 0);
        }
    </script>
    <script>
        if (browserSupportCSSVariables) {
            var customFontName = 'Noto Sans SC:n3,n4,n5,n7'
            var customFontUrl = 'https://fonts.googleapis.cnpmjs.org/css2?family=Noto+Sans+SC:wght@300;400;500;700&amp;display=swap'
            if (!customFontName) {
                console.log('Custom font name is not set or read failed');
            }
            if (!customFontUrl) {
                console.log('Custom font url is not set or read failed');
            }
        } else {
            console.error('Current browser doesn\'t support custom font.')
        }
    </script>
    <script src="/scripts/customFontLoader.js?v=20211217" defer></script>


        <!-- main func -->
        <script src="/scripts/main.js?v=20211217"></script>
        <!-- dark mode -->
        <script src="/scripts/dark.js?v=20211217"></script>
        <!-- fancybox -->
        <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" defer></script>
        <!-- algolia -->
        
            <div class="site-search site-search-loading">
    <div class="algolia-popup popup">
        <div class="algolia-search">
            <div class="algolia-search-input-icon">
                <i class="fa fa-search"></i>
            </div>
            <div class="algolia-search-input" id="algolia-search-input"></div>
            <div class="popup-btn-close">
                <i class="iconfont-archer">&#xe609;</i>
            </div>
        </div>

        <div class="algolia-results">
            <div id="algolia-stats" class="algolia-stats"></div>
            <div id="algolia-hits"></div>
            <div id="algolia-pagination" class="algolia-pagination"></div>
        </div>
    </div>
</div>

            <script src="/scripts/search.js?v=20211217" defer></script>
        
        <!-- busuanzi -->
        
            <script src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script>
        
        <!-- CNZZ -->
        
        <!-- async load share.js -->
        
            <script src="/scripts/share.js?v=20211217" async></script>
        
        <!-- mermaid -->
        
    </body>
</html>
